﻿package baseEngine.utils
{
    import __AS3__.vec.*;
    import flash.geom.*;

    public class Matrix3DUtils extends Object
    {
        private static var _toRad:Number = 0.0174533;
        private static var _toAng:Number = 57.2958;
        private static var _vector:Vector3D = new Vector3D();
        private static var _right:Vector3D = new Vector3D();
        private static var _up:Vector3D = new Vector3D();
        private static var _dir:Vector3D = new Vector3D();
        private static var _scale:Vector3D = new Vector3D();
        private static var _pos:Vector3D = new Vector3D();
        private static var _x:Number;
        private static var _y:Number;
        private static var _z:Number;

        public function Matrix3DUtils()
        {
            return;
        }// end function

        public static function getRight(param1:Matrix3D, param2:Vector3D = null) : Vector3D
        {
            if (param2 == null)
            {
                param2 = new Vector3D();
            }
            param1.copyColumnTo(0, param2);
            return param2;
        }// end function

        public static function getUp(param1:Matrix3D, param2:Vector3D = null) : Vector3D
        {
            if (param2 == null)
            {
                param2 = new Vector3D();
            }
            param1.copyColumnTo(1, param2);
            return param2;
        }// end function

        public static function getDir(param1:Matrix3D, param2:Vector3D = null) : Vector3D
        {
            if (param2 == null)
            {
                param2 = new Vector3D();
            }
            param1.copyColumnTo(2, param2);
            return param2;
        }// end function

        public static function getLeft(param1:Matrix3D, param2:Vector3D = null) : Vector3D
        {
            if (param2 == null)
            {
                param2 = new Vector3D();
            }
            param1.copyColumnTo(0, param2);
            param2.negate();
            return param2;
        }// end function

        public static function getDown(param1:Matrix3D, param2:Vector3D = null) : Vector3D
        {
            if (param2 == null)
            {
                param2 = new Vector3D();
            }
            param1.copyColumnTo(1, param2);
            param2.negate();
            return param2;
        }// end function

        public static function getBackward(param1:Matrix3D, param2:Vector3D = null) : Vector3D
        {
            if (param2 == null)
            {
                param2 = new Vector3D();
            }
            param1.copyColumnTo(2, param2);
            param2.negate();
            return param2;
        }// end function

        public static function getPosition(param1:Matrix3D, param2:Vector3D = null) : Vector3D
        {
            if (param2 == null)
            {
                param2 = new Vector3D();
            }
            param1.copyColumnTo(3, param2);
            return param2;
        }// end function

        public static function getScale(param1:Matrix3D, param2:Vector3D = null) : Vector3D
        {
            if (!param2)
            {
                param2 = new Vector3D();
            }
            param1.copyColumnTo(0, _right);
            param1.copyColumnTo(1, _up);
            param1.copyColumnTo(2, _dir);
            param2.x = _right.length;
            param2.y = _up.length;
            param2.z = _dir.length;
            return param2;
        }// end function

        public static function setPosition(param1:Matrix3D, param2:Number, param3:Number, param4:Number, param5:Number = 1) : void
        {
            if (param5 == 1)
            {
                _vector.setTo(param2, param3, param4);
                _vector.w = 1;
                param1.copyColumnFrom(3, _vector);
            }
            else
            {
                param1.copyColumnTo(3, _pos);
                _pos.x = _pos.x + (param2 - _pos.x) * param5;
                _pos.y = _pos.y + (param3 - _pos.y) * param5;
                _pos.z = _pos.z + (param4 - _pos.z) * param5;
                param1.copyColumnFrom(3, _pos);
            }
            return;
        }// end function

        public static function setOrientation(param1:Matrix3D, param2:Vector3D, param3:Vector3D = null, param4:Number = 1) : void
        {
            getScale(param1, _scale);
            if (param3 == null)
            {
                if (param2.x == 0 && Math.abs(param2.y) == 1 && param2.z == 0)
                {
                    param3 = Vector3D.Z_AXIS;
                }
                else
                {
                    param3 = Vector3D.Y_AXIS;
                }
            }
            if (param4 != 1)
            {
                getDir(param1, _dir);
                _dir.x = _dir.x + (param2.x - _dir.x) * param4;
                _dir.y = _dir.y + (param2.y - _dir.y) * param4;
                _dir.z = _dir.z + (param2.z - _dir.z) * param4;
                param2 = _dir;
                getUp(param1, _up);
                _up.x = _up.x + (param3.x - _up.x) * param4;
                _up.y = _up.y + (param3.y - _up.y) * param4;
                _up.z = _up.z + (param3.z - _up.z) * param4;
                param3 = _up;
            }
            param2.normalize();
            var _loc_5:* = param3.crossProduct(param2);
            _loc_5.normalize();
            param3 = param2.crossProduct(_loc_5);
            _loc_5.scaleBy(_scale.x);
            param3.scaleBy(_scale.y);
            param2.scaleBy(_scale.z);
            setVectors(param1, _loc_5, param3, param2);
            return;
        }// end function

        public static function setNormalOrientation(param1:Matrix3D, param2:Vector3D, param3:Number = 1) : void
        {
            if (param2.x == 0 && param2.y == 0 && param2.z == 0)
            {
                return;
            }
            getScale(param1, _scale);
            getDir(param1, _dir);
            if (param3 != 1)
            {
                getUp(param1, _up);
                _up.x = _up.x + (param2.x - _up.x) * param3;
                _up.y = _up.y + (param2.y - _up.y) * param3;
                _up.z = _up.z + (param2.z - _up.z) * param3;
                param2 = _up;
            }
            param2.normalize();
            var _loc_4:* = Math.abs(_dir.dotProduct(param2)) == 1 ? (getRight(param1, _right)) : (_dir);
            var _loc_5:* = param2.crossProduct(_loc_4);
            _loc_5.normalize();
            var _loc_6:* = _loc_5.crossProduct(param2);
            _loc_5.scaleBy(_scale.x);
            param2.scaleBy(_scale.y);
            _loc_6.scaleBy(_scale.z);
            setVectors(param1, _loc_5, param2, _loc_6);
            return;
        }// end function

        public static function setVectors(param1:Matrix3D, param2:Vector3D, param3:Vector3D, param4:Vector3D) : void
        {
            param2.w = 0;
            param3.w = 0;
            param4.w = 0;
            param1.copyColumnFrom(0, param2);
            param1.copyColumnFrom(1, param3);
            param1.copyColumnFrom(2, param4);
            return;
        }// end function

        public static function lookAt(param1:Matrix3D, param2:Number, param3:Number, param4:Number, param5:Vector3D = null, param6:Number = 1) : void
        {
            param1.copyColumnTo(3, _pos);
            _vector.x = param2 - _pos.x;
            _vector.y = param3 - _pos.y;
            _vector.z = param4 - _pos.z;
            setOrientation(param1, _vector, param5, param6);
            return;
        }// end function

        public static function setTranslation(param1:Matrix3D, param2:Number = 0, param3:Number = 0, param4:Number = 0, param5:Boolean = true) : void
        {
            if (param5)
            {
                param1.prependTranslation(param2, param3, param4);
            }
            else
            {
                param1.appendTranslation(param2, param3, param4);
            }
            return;
        }// end function

        public static function translateX(param1:Matrix3D, param2:Number, param3:Boolean = true) : void
        {
            param1.copyColumnTo(3, _pos);
            param1.copyColumnTo(0, _right);
            if (param3)
            {
                _pos.x = _pos.x + param2 * _right.x;
                _pos.y = _pos.y + param2 * _right.y;
                _pos.z = _pos.z + param2 * _right.z;
            }
            else
            {
                _pos.x = _pos.x + param2;
            }
            param1.copyColumnFrom(3, _pos);
            return;
        }// end function

        public static function translateY(param1:Matrix3D, param2:Number, param3:Boolean = true) : void
        {
            param1.copyColumnTo(3, _pos);
            param1.copyColumnTo(1, _up);
            if (param3)
            {
                _pos.x = _pos.x + param2 * _up.x;
                _pos.y = _pos.y + param2 * _up.y;
                _pos.z = _pos.z + param2 * _up.z;
            }
            else
            {
                _pos.y = _pos.y + param2;
            }
            param1.copyColumnFrom(3, _pos);
            return;
        }// end function

        public static function translateZ(param1:Matrix3D, param2:Number, param3:Boolean = true) : void
        {
            param1.copyColumnTo(3, _pos);
            param1.copyColumnTo(2, _dir);
            if (param3)
            {
                _pos.x = _pos.x + param2 * _dir.x;
                _pos.y = _pos.y + param2 * _dir.y;
                _pos.z = _pos.z + param2 * _dir.z;
            }
            else
            {
                _pos.z = _pos.z + param2;
            }
            param1.copyColumnFrom(3, _pos);
            return;
        }// end function

        public static function translateAxis(param1:Matrix3D, param2:Number, param3:Vector3D) : void
        {
            param1.copyColumnTo(3, _pos);
            _pos.x = _pos.x + param2 * param3.x;
            _pos.y = _pos.y + param2 * param3.y;
            _pos.z = _pos.z + param2 * param3.z;
            param1.copyColumnFrom(3, _pos);
            return;
        }// end function

        public static function setScale(param1:Matrix3D, param2:Number, param3:Number, param4:Number, param5:Number = 1) : void
        {
            getScale(param1, _scale);
            _x = _scale.x;
            _y = _scale.y;
            _z = _scale.z;
            _scale.x = _scale.x + (param2 - _scale.x) * param5;
            _scale.y = _scale.y + (param3 - _scale.y) * param5;
            _scale.z = _scale.z + (param4 - _scale.z) * param5;
            _right.scaleBy(_scale.x / _x);
            _up.scaleBy(_scale.y / _y);
            _dir.scaleBy(_scale.z / _z);
            setVectors(param1, _right, _up, _dir);
            return;
        }// end function

        public static function scaleX(param1:Matrix3D, param2:Number) : void
        {
            param1.copyColumnTo(0, _right);
            _right.normalize();
            _right.x = _right.x * param2;
            _right.y = _right.y * param2;
            _right.z = _right.z * param2;
            param1.copyColumnFrom(0, _right);
            return;
        }// end function

        public static function scaleY(param1:Matrix3D, param2:Number) : void
        {
            param1.copyColumnTo(1, _up);
            _up.normalize();
            _up.x = _up.x * param2;
            _up.y = _up.y * param2;
            _up.z = _up.z * param2;
            param1.copyColumnFrom(1, _up);
            return;
        }// end function

        public static function scaleZ(param1:Matrix3D, param2:Number) : void
        {
            param1.copyColumnTo(2, _dir);
            _dir.normalize();
            _dir.x = _dir.x * param2;
            _dir.y = _dir.y * param2;
            _dir.z = _dir.z * param2;
            param1.copyColumnFrom(2, _dir);
            return;
        }// end function

        public static function getRotation(param1:Matrix3D, param2:Vector3D = null) : Vector3D
        {
            param2 = param2 || new Vector3D();
            _vector = param1.decompose(Orientation3D.EULER_ANGLES)[1];
            param2.x = _vector.x * _toAng;
            param2.y = _vector.y * _toAng;
            param2.z = _vector.z * _toAng;
            return param2;
        }// end function

        public static function setRotation(param1:Matrix3D, param2:Number, param3:Number, param4:Number) : void
        {
            var _loc_5:* = param1.decompose(Orientation3D.EULER_ANGLES);
            _loc_5[1].x = param2 * _toRad;
            _loc_5[1].y = param3 * _toRad;
            _loc_5[1].z = param4 * _toRad;
            param1.recompose(_loc_5, Orientation3D.EULER_ANGLES);
            return;
        }// end function

        public static function rotateX(param1:Matrix3D, param2:Number, param3:Boolean = true, param4:Vector3D = null) : void
        {
            rotateAxis(param1, param2, param3 ? (getRight(param1, _vector)) : (Vector3D.X_AXIS), param4);
            return;
        }// end function

        public static function rotateY(param1:Matrix3D, param2:Number, param3:Boolean = true, param4:Vector3D = null) : void
        {
            rotateAxis(param1, param2, param3 ? (getUp(param1, _vector)) : (Vector3D.Y_AXIS), param4);
            return;
        }// end function

        public static function rotateZ(param1:Matrix3D, param2:Number, param3:Boolean = true, param4:Vector3D = null) : void
        {
            rotateAxis(param1, param2, param3 ? (getDir(param1, _vector)) : (Vector3D.Z_AXIS), param4);
            return;
        }// end function

        public static function rotateAxis(param1:Matrix3D, param2:Number, param3:Vector3D, param4:Vector3D = null) : void
        {
            _vector.x = param3.x;
            _vector.y = param3.y;
            _vector.z = param3.z;
            _vector.normalize();
            param1.copyColumnTo(3, _pos);
            param1.appendRotation(param2, _vector, param4 || _pos);
            return;
        }// end function

        public static function transformVector(param1:Matrix3D, param2:Vector3D, param3:Vector3D = null) : Vector3D
        {
            if (!param3)
            {
                param3 = new Vector3D();
            }
            _vector.copyFrom(param2);
            param1.copyRowTo(0, _right);
            param1.copyRowTo(1, _up);
            param1.copyRowTo(2, _dir);
            param1.copyColumnTo(3, param3);
            param3.x = param3.x + (_vector.x * _right.x + _vector.y * _right.y + _vector.z * _right.z);
            param3.y = param3.y + (_vector.x * _up.x + _vector.y * _up.y + _vector.z * _up.z);
            param3.z = param3.z + (_vector.x * _dir.x + _vector.y * _dir.y + _vector.z * _dir.z);
            return param3;
        }// end function

        public static function deltaTransformVector(param1:Matrix3D, param2:Vector3D, param3:Vector3D = null) : Vector3D
        {
            if (!param3)
            {
                param3 = new Vector3D();
            }
            _vector.copyFrom(param2);
            param1.copyRowTo(0, _right);
            param1.copyRowTo(1, _up);
            param1.copyRowTo(2, _dir);
            param3.x = _vector.x * _right.x + _vector.y * _right.y + _vector.z * _right.z;
            param3.y = _vector.x * _up.x + _vector.y * _up.y + _vector.z * _up.z;
            param3.z = _vector.x * _dir.x + _vector.y * _dir.y + _vector.z * _dir.z;
            return param3;
        }// end function

        public static function invert(param1:Matrix3D, param2:Matrix3D = null) : Matrix3D
        {
            if (!param2)
            {
                param2 = new Matrix3D();
            }
            param2.copyFrom(param1);
            param2.invert();
            return param2;
        }// end function

        public static function equal(param1:Matrix3D, param2:Matrix3D) : Boolean
        {
            var _loc_5:int = 0;
            var _loc_3:* = param1.rawData;
            var _loc_4:* = param2.rawData;
            while (_loc_5 < 16)
            {
                
                if (_loc_3[_loc_5] != _loc_4[_loc_5])
                {
                    return false;
                }
                _loc_5++;
            }
            return true;
        }// end function

        public static function interpolateTo(param1:Matrix3D, param2:Matrix3D, param3:Number) : void
        {
            Matrix3DUtils.getScale(param1, _scale);
            Matrix3DUtils.getScale(param2, _vector);
            _scale.x = _scale.x + (_vector.x - _scale.x) * param3;
            _scale.y = _scale.y + (_vector.y - _scale.y) * param3;
            _scale.z = _scale.z + (_vector.z - _scale.z) * param3;
            param1.interpolateTo(param2, param3);
            param1.prependScale(_scale.x, _scale.y, _scale.z);
            return;
        }// end function

        public static function resetPosition(param1:Matrix3D) : void
        {
            setPosition(param1, 0, 0, 0);
            return;
        }// end function

        public static function resetRotation(param1:Matrix3D) : void
        {
            setRotation(param1, 0, 0, 0);
            return;
        }// end function

        public static function resetScale(param1:Matrix3D) : void
        {
            setScale(param1, 1, 1, 1);
            return;
        }// end function

    }
}
